package edu.gmu.middleware;

import edu.gmu.streams.BlockOutputStream;
import edu.gmu.streams.ByteBufferOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * The MarshalerImpl object will take a Message Object and
 * marshal it into a byte[].  The byte[] will include a
 * header and is usually passed over middleware via a socket though nothing
 * prevents other outputs (e.g. file).
 * 
 * @author  James H. Pope
 * @version $Revision:$ $Date:$
 */
public class MarshalerImpl implements Marshaler
{
    /**
     * Creates an instance of MarshalerImpl
     */
    public MarshalerImpl( )
    {
        
    }

    /**
     * Marshals the given message into the given buffer.
     * @param header (caller sets desired endian-order and topic)
     * @param message
     * @param out
     * @throws IOException If there is an error marshaling the message
     */
    public void marshal(    Header header,
                            Message message,
                            ByteBuffer out) throws IOException
    {
        // Reset buffer
        out.clear();
        
        
        // Set correct endian order
        if( header.getEndianFlag() == EndianFlag.LITTLE_ENDIAN )
        {
            out.order( ByteOrder.LITTLE_ENDIAN );
        }
        else
        {
            out.order( ByteOrder.BIG_ENDIAN );
        
        }
        BlockOutputStream outputStream = new ByteBufferOutputStream( out );
        // Write out zeroes for the header until the end
        outputStream.skipBytes(Header.SIZEOF);
        
        /*
         * Marshal the message attributes to the stream
         */
        message.marshal(outputStream);
        
        /*
         * Overwrite beginning bytes with that of the header with proper length.
         */
        int length = out.position();
        header.setLength(length);
        out.position(0);
        header.marshal(out);
        out.position( length );
        
        //System.out.println( "Marshal: packet.length="+length );
        
        //return out;
    }
}
